// scaup - Scala up!
// (c) 2008-2010, Normen Müller, normen.mueller@gmail.com  
// $Id: graphs.scala 47 2010-01-12 20:22:35Z normen.mueller $
package scaup.data.graph

import scaup._

import collection._

/** Base for class for graph
 * 
 * @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 * @version 0.0.5 */
abstract class AbstractGraph {
  //private val annos: mutable.Map[String, String] = mutable.Map()
  private val nodes: mutable.Map[Id, V] = mutable.Map()
  private val edges: mutable.Map[Id, E] = mutable.Map()
  
  /** Abstract type of node and edge identifiers 
   */
  type Id
  
  /** Abstract type of graph nodes
   */
  type V <: AbstractNode
  abstract class AbstractNode extends INode[V,E] with Identifiable[Id]
  
  /** Abstract type of graph edges
   */
  type E <: AbstractEdge
  abstract class AbstractEdge extends IEdge[V] with Identifiable[Id]
  
  /** Node constructor
   */
  def η(id: Id): V
  
  /** Set of nodes
   */
  lazy val V: Set[V] = Set.empty[V] ++ nodes.values
  
  /** Set of edges
   */
  lazy val E: Set[E] = Set.empty[E] ++ edges.values 
  
  /** Add a new node to the graph
   * 
   *  If <code>n</code> already exists, then <code>n</code>'s annotations are merged with existing ones.
   * 
   * @param n New node to add
   * @return Graph with additional node <code>n</code>
   */
  def += (n: V) = addNode(n)
  def addNode(n: V): this.type = {
    nodes += {(n.id, n)}
    this
  }
  
  /** Add a new edge to the graph
   * 
   *  If <code>e</code> already exists, then <code>e</code>'s annotations are merged with existing ones.
   * 
   * @param e New edge to add
   * @return Graph with additional node <code>n</code>
   */
  def += (e: E) = addEdge(e)
  def addEdge(e: E): this.type = {
    nodes ++= List({(e.↑.id, e.↑)}, {(e.↓.id, e.↓)})
    
    nodes(e.↑.id).outgoing += e
    nodes(e.↓.id).incomming += e
    
    edges += {(e.↑.id, e)}
    
    this      
  }  
}
